package stockin

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
	"sync"
	"wms/model"

	"wms/internal/svc"
	"wms/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type StockinUpdateLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewStockinUpdateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StockinUpdateLogic {
	return &StockinUpdateLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *StockinUpdateLogic) StockinUpdate(req *types.StockInUpdateRequest) (resp *types.BaseResponse, err error) {
	resp = new(types.BaseResponse)
	//1.入库单是否存在
	_, err = l.svcCtx.StockInModel.FindOne(l.ctx, req.Id)
	switch err {
	case nil:
	case model.ErrNotFound:
		fmt.Printf("[Error]入库单[%d]不存在\n", req.Id)
		resp.Code = http.StatusBadRequest
		resp.Msg = "入库单不存在"
		return resp, nil
	default:
		fmt.Printf("[Error]查询入库单[%d]:%s\n", req.Id, err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}
	//2.供货商是否存在
	supplier, err := l.svcCtx.SupplierModel.FindOne(l.ctx, req.SupplierId)
	switch err {
	case nil:
	case model.ErrNotFound:
		fmt.Printf("[Error]供货商[%d]不存在\n", req.SupplierId)
		resp.Code = http.StatusBadRequest
		resp.Msg = "供货商不存在"
		return resp, nil
	default:
		fmt.Printf("[Error]查询供货商[%d]:%s\n", req.SupplierId, err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	//3.原料类型是否存在
	var mux sync.RWMutex
	var g errgroup.Group
	var materials = make(map[int64]model.Materials)
	for _, detail := range req.List {
		one := detail
		g.Go(func() error {
			material, e := l.svcCtx.MaterialsModel.FindOne(l.ctx, one.MaterialsId)
			switch e {
			case nil:
				mux.Lock()
				materials[one.MaterialsId] = *material
				mux.Unlock()
			case model.ErrNotFound:
				fmt.Printf("[Error]原料类型[%d]不存在\n", one.MaterialsId)
			default:
				fmt.Printf("[Error]查询原料类型[%d]:%s\n", one.MaterialsId, e.Error())
			}
			return e
		})
	}

	err = g.Wait()
	switch err {
	case nil:
	case model.ErrNotFound:
		resp.Code = http.StatusBadRequest
		resp.Msg = "原料类型不存在"
		return resp, nil
	default:
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	//4.计算总金额
	if len(req.List) == 0 {
		resp.Code = http.StatusBadRequest
		resp.Msg = "请添加入库原料"
		return resp, nil
	}
	var total float64
	for _, detail := range req.List {
		//单价（元）*数量（吨）
		total += detail.Price * detail.Weight
	}
	//5.更新stock_in表
	var date int64
	var tax int64

	if req.Status == 2 {
		date = req.Date
	}
	if req.HasTax {
		tax = req.Tax
	}

	err = l.svcCtx.StockInModel.Update(l.ctx, &model.StockIn{
		Id:            req.Id,
		SupplierId:    req.SupplierId,
		SupplierName:  supplier.Name,
		Status:        req.Status,
		BalanceStatus: req.BalanceStatus,
		HasTax:        req.HasTax,
		Tax:           tax,
		Total:         total,
		Deposit:       req.Deposit,
		Date:          date,
	})
	if err != nil {
		fmt.Printf("[Error]更新入库单[%d]:%s\n", req.Id, err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}
	//6.删除stock_in_detail表
	details, err := l.svcCtx.StockInDetailModel.FindByPage(l.ctx, fmt.Sprintf(" where stock_id=%d", req.Id))
	switch err {
	case nil:
	case model.ErrNotFound:
	default:
		fmt.Printf("[Error]查询入库单[%d]原料列表:%s\n", req.Id, err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	for _, detail := range details {
		one := detail
		g.Go(func() error {
			e := l.svcCtx.StockInDetailModel.Delete(l.ctx, one.Id)
			if e != nil {
				fmt.Printf("[Error]删除入库单[%d]详情[%d]:%s\n", req.Id, one.Id, e.Error())
			}
			return e
		})
	}

	err = g.Wait()
	if err != nil {
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}
	//7.写入stock_in_detail表
	for _, detail := range req.List {
		one := detail
		g.Go(func() error {
			_, e := l.svcCtx.StockInDetailModel.Insert(l.ctx, &model.StockInDetail{
				StockId:        req.Id,
				MaterialsId:    one.MaterialsId,
				MaterialsName:  materials[one.MaterialsId].Name,
				MaterialsTypes: materials[one.MaterialsId].Types,
				Weight:         one.Weight,
				Price:          one.Price,
			})
			if e != nil {
				fmt.Printf("[Error]写入入库单[%d]原料[%d]:%s\n", req.Id, one.MaterialsId, e.Error())
			}
			return e
		})
	}

	err = g.Wait()
	if err != nil {
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	resp.Code = http.StatusOK
	resp.Msg = "成功"
	return resp, nil
}
